﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Net;
using System.Web;
using System.Web.Hosting;
using System.IO;
using System.Reflection;
using System.Security;
using System.Collections;
using System.Threading;

namespace PickGold.Web
{
	/// <summary>
	/// 为Http协议请求提供基本服务
	/// </summary>
	public abstract class HttpWebServer : MarshalByRefObject
	{
		private static Hashtable _Item;
		/// <summary>
		/// 默认实列
		/// </summary>
		protected static HttpWebServer _Value;

		/// <summary>
		/// HttpListener
		/// </summary>
		protected HttpListener _HttpListener;
		/// <summary>
		/// 物理路径
		/// </summary>
		protected string _PhysicalPath;
		/// <summary>
		/// 虚拟目录
		/// </summary>
		protected string _VirtualPath;
		/// <summary>
		/// 状态
		/// </summary>
		protected int _State;
		/// <summary>
		/// 处理计数
		/// </summary>
		protected int _Count;

		/// <summary>
		/// 构造服务实例
		/// </summary>
		public HttpWebServer()
		{
			HttpWebServer._Value = this;
			this._HttpListener = new HttpListener();
			this._PhysicalPath = null;
			this._VirtualPath = null;
			this._State = -1;
			this._Count = 0;
			this._HttpListener.Start();
		}

		/// <summary>
		/// 获取物理路径
		/// </summary>
		public string PhysicalPath
		{
			protected set
			{
				this._PhysicalPath = value;
			}
			get
			{
				return this._PhysicalPath;
			}
		}

		/// <summary>
		/// 获取物理路径
		/// </summary>
		public string VirtualPath
		{
			protected set
			{
				this._VirtualPath = value;
			}
			get
			{
				return this._VirtualPath;
			}
		}

		/// <summary>
		/// 获取由此 System.Net.HttpListener 对象处理的统一资源标识符 (URI) 前缀。
		/// </summary>
		public HttpListenerPrefixCollection Prefixes
		{
			get
			{
				return this._HttpListener.Prefixes;
			}
		}

		/// <summary>
		/// 设置全局附加数据
		/// </summary>
		/// <param name="key">键</param>
		/// <param name="value">值</param>
		public void SetApplicationItem(object key, object value)
		{
			HttpWebServer.SetItem(key, value);
		}

		/// <summary>
		/// 获取全局附加数据
		/// </summary>
		/// <param name="key">键</param>
		/// <returns>值</returns>
		public object GetApplicationItem(object key)
		{
			return HttpWebServer.GetItem(key);
		}

		/// <summary>
		/// 将一个统一资源标识符 (URI) 前缀添加到该集合中。
		/// </summary>
		/// <param name="domainOrIP">DNS域名、计算机名或 IP 地址</param>
		/// <param name="port">端口，小于等于零则为默认端口：80</param>
		public void AddPrefixe(string domainOrIP, int port)
		{
			if (string.IsNullOrEmpty(domainOrIP) && port <= 0)
				this.AddPrefixe(null);
			else if (string.IsNullOrEmpty(domainOrIP))
				this.AddPrefixe("+:" + port);
			else if (port <= 0)
				this.AddPrefixe(domainOrIP);
			else
				this.AddPrefixe(domainOrIP + ":" + port);
		}
		/// <summary>
		/// 将一个统一资源标识符 (URI) 前缀添加到该集合中。
		/// </summary>
		/// <param name="uriPrefixe">标识在传入的请求中进行比较的 URI 信息。</param>
		public void AddPrefixe(string uriPrefixe)
		{
			if (string.IsNullOrEmpty(uriPrefixe))
			{
				this._HttpListener.Prefixes.Add("http://+/");
				return;
			}

			if (!uriPrefixe.StartsWith("http://", StringComparison.OrdinalIgnoreCase) &&
				!uriPrefixe.StartsWith("https://", StringComparison.OrdinalIgnoreCase))
				uriPrefixe = "http://" + uriPrefixe;
			if (uriPrefixe[uriPrefixe.Length - 1] != '/')
				uriPrefixe = uriPrefixe + "/";
			if (this._HttpListener.Prefixes.Contains(uriPrefixe))
				return;

			this._HttpListener.Prefixes.Add(uriPrefixe);
		}
		/// <summary>
		/// 将一个统一资源标识符 (URI) 前缀添加到该集合中。测试80端口，然后探测8000以后所有端口，直到成功为止
		/// </summary>
		public void AddPrefixe()
		{
			try
			{
				this.AddPrefixe(null);
				return;
			}
			catch { }

			for (var i = 8000; ; i++)
			{
				try
				{
					this.AddPrefixe(null, i);
					return;
				}
				catch (SecurityException)
				{
					throw;
				}
				catch// (Exception x)
				{
				}
			}
		}

		/// <summary>
		/// 开始服务
		/// </summary>
		public virtual void Start()
		{
			if (this._State == 0)
				this._HttpListener.Start();
			if (this._State == 1)
				return;

			this._State = 1;
			this._HttpListener.BeginGetContext(this.EndGetContext, this._HttpListener);
		}

		/// <summary>
		/// 暂停服务
		/// </summary>
		public virtual void Pause()
		{
			this._State = -1;
		}

		/// <summary>
		/// 停止服务
		/// </summary>
		public virtual void Stop()
		{
			this._State = 0;
			this._HttpListener.Stop();
		}

		/// <summary>
		/// 完成检索传入的客户端请求的异步操作。
		/// </summary>
		/// <param name="result">启动异步操作时获得的 System.IAsyncResult 对象。</param>
		protected void EndGetContext(IAsyncResult result)
		{
			if (Thread.CurrentThread.IsThreadPoolThread && Fiber.QueueUserAsyncCallback(this.EndGetContext, result))
				return;

			var hl = result.AsyncState as HttpListener;
			try
			{
				var context = hl.EndGetContext(result);
				Fiber.QueueUserWorkItem(new WaitCallback(state =>
					{
						try
						{
							this.OnEndGetContext(context);
						}
						catch { }//500
						context.Response.Close();
						this._Count++;
					}), context);
			}
			catch { }
			if (this._State > 0)
				hl.BeginGetContext(this.EndGetContext, hl);
		}

		/// <summary>
		/// 完成检索传入的客户端请求的异步操作。
		/// </summary>
		/// <param name="context">提供对 System.Net.HttpListener 类使用的请求和响应对象的访问实例</param>
		protected abstract void OnEndGetContext(HttpListenerContext context);

		/// <summary>
		/// 全局附加数据
		/// </summary>
		public static Hashtable Item
		{
			get
			{
				if (HttpWebServer._Item == null)
					HttpWebServer._Item = new Hashtable();
				return HttpWebServer._Item;
			}
		}

		/// <summary>
		/// 设置全局附加数据
		/// </summary>
		/// <param name="key">键</param>
		/// <param name="value">值</param>
		public static void SetItem(object key, object value)
		{
			if (HttpWebServer._Item == null)
				HttpWebServer._Item = new Hashtable();
			HttpWebServer._Item[key] = value;
		}

		/// <summary>
		/// 获取全局附加数据
		/// </summary>
		/// <param name="key">键</param>
		/// <returns>值</returns>
		public static object GetItem(object key)
		{
			if (HttpWebServer._Item == null)
				return null;

			if (HttpWebServer._Item.ContainsKey(key))
				return HttpWebServer._Item[key];

			return null;
		}

		/// <summary>
		/// 取物理路径
		/// </summary>
		/// <param name="physicalPath"物理路径></param>
		/// <returns>物理路径</returns>
		protected static string GetPhysicalPath(string physicalPath)
		{
			if (!string.IsNullOrEmpty(physicalPath))
				return physicalPath;

			try
			{
				if (string.IsNullOrEmpty(physicalPath))
					physicalPath = Path.GetDirectoryName(typeof(HttpWebServer).Assembly.Location);
			}
			catch { }
			try
			{
				if (string.IsNullOrEmpty(physicalPath))
					physicalPath = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location);
			}
			catch { }
			if (string.IsNullOrEmpty(physicalPath))
				physicalPath = Environment.CurrentDirectory;
			if (string.Compare(Path.GetFileName(physicalPath), "bin", true) == 0 && !Directory.Exists(Path.Combine(physicalPath, "bin")))
				return Path.GetDirectoryName(physicalPath);

			return physicalPath;
		}

		/// <summary>
		/// 取虚拟目录
		/// </summary>
		/// <param name="virtualPath">虚拟目录</param>
		/// <returns>虚拟目录</returns>
		protected static string GetVirtualPath(string virtualPath)
		{
			if (string.IsNullOrEmpty(virtualPath))
				return "/";

			return virtualPath;
		}
	}

	/// <summary>
	/// 动态页新域处理服务
	/// </summary>
	public class AspxWebServer : HttpWebServer
	{
		/// <summary>
		/// 完成检索传入的客户端请求的异步操作。
		/// </summary>
		/// <param name="context">提供对 System.Net.HttpListener 类使用的请求和响应对象的访问实例</param>
		protected override void OnEndGetContext(HttpListenerContext context)
		{
			var workerRequest = new WebWorkerRequest(context, this);
			HttpRuntime.ProcessRequest(workerRequest);
		}

		/// <summary>
		/// 使用当前路径与根虚拟目录“/”创建服务
		/// </summary>
		/// <returns>HttpWebServer</returns>
		public static AspxWebServer Create()
		{
			return AspxWebServer.Create(null, null);
		}
		/// <summary>
		/// 使用指定的物理路径与根虚拟目录“/”创建服务
		/// </summary>
		/// <param name="physicalPath">物理路径</param>
		/// <returns>HttpWebServer</returns>
		public static AspxWebServer Create(string physicalPath)
		{
			return AspxWebServer.Create(physicalPath, null);
		}
		/// <summary>
		/// 使用指定的物理路径与指定的虚拟目录创建服务
		/// </summary>
		/// <param name="physicalPath">物理路径</param>
		/// <param name="virtualPath">虚拟目录</param>
		/// <returns>HttpWebServer</returns>
		public static AspxWebServer Create(string physicalPath, string virtualPath)
		{
			physicalPath = HttpWebServer.GetPhysicalPath(physicalPath);
			virtualPath = HttpWebServer.GetVirtualPath(virtualPath);
			var result = ApplicationHost.CreateApplicationHost(typeof(AspxWebServer), virtualPath, physicalPath);
			var value = result as AspxWebServer;
			value.PhysicalPath = physicalPath;
			value.VirtualPath = virtualPath;
			return value;
		}
	}

	/// <summary>
	/// 静态页本地处理服务
	/// </summary>
	public class HtmlWebServer : HttpWebServer
	{
		/// <summary>
		/// 取得请求事件
		/// </summary>
		public event EventHandler<EndContextGetEventArgs> EndContextGet;

		/// <summary>
		/// 完成检索传入的客户端请求的异步操作。
		/// </summary>
		/// <param name="context">提供对 System.Net.HttpListener 类使用的请求和响应对象的访问实例</param>
		protected override void OnEndGetContext(HttpListenerContext context)
		{
			if (this.EndContextGet == null)
				return;

			var e = new EndContextGetEventArgs(context);
			this.EndContextGet(this, e);
		}
	}

	/// <summary>
	/// 取得请求事件参数
	/// </summary>
	public class EndContextGetEventArgs : EventArgs
	{
		private HttpListenerContext _Context;

		/// <summary>
		/// 构造一取得请求事件参数实例
		/// </summary>
		/// <param name="context"></param>
		public EndContextGetEventArgs(HttpListenerContext context)
		{
			this._Context = context;
		}

		/// <summary>
		/// 提供对 System.Net.HttpListener 类使用的请求和响应对象的访问实例
		/// </summary>
		public HttpListenerContext Context
		{
			get
			{
				return this._Context;
			}
		}
	}
}
